#include "bind.h"
#include <list>
#include "gge.h"
#include "scheduler.h"
using namespace gge;

////////////////////////////////////////////////////////////////////////// sys
ccc_bind_declspec auto gge_createEngine(int w, int h, int fps)
{
	if (!Engine_Create())
	{
		return false;
	}
//	System_SetState(GGE_LOGNAME, __argv[0]);
//	System_SetState(GGE_DEBUGLOG, false);
	System_SetState(GGE_TITLE, "gge so easy");
	System_SetState(GGE_SCREENWIDTH, w);
	System_SetState(GGE_SCREENHEIGHT, h);
	System_SetState(GGE_FPS, fps);
	System_SetState(GGE_ICON, 101);
	System_SetState(GGE_HIDEMOUSE, false);
	return System_Initiate();
}

static bool gge_frame();
static bool gge_exit();
static bool gge_message(HWND h, UINT u, WPARAM w, LPARAM l);
ccc_bind_declspec auto gge_callback()
{
	System_SetState(GGE_FRAMEFUNC, gge_frame);
	System_SetState(GGE_EXITFUNC, gge_exit);
	System_SetState(GGE_MESSAGEFUNC, gge_message);
}
ccc_bind_declspec auto gge_setWindowSize(int w, int h) { System_SetState(GGE_SCREENWIDTH, w); return System_SetState(GGE_SCREENHEIGHT, h); }
ccc_bind_declspec auto gge_hideMouse(bool hide) { return System_SetState(GGE_HIDEMOUSE, hide); }
ccc_bind_declspec auto gge_debugLog(bool log) { return System_SetState(GGE_DEBUGLOG, log); }
ccc_bind_declspec auto gge_forceTexturefilter(bool force) { return System_SetState(GGE_FORCETEXFILTER, force); }
ccc_bind_declspec auto gge_setWindowTitle(const char* title) { return System_SetState(GGE_TITLE, title); }
ccc_bind_declspec auto gge_getHwnd() { return (sPointer)System_GetState(GGE_HWND); }
// System_Log
ccc_bind_declspec auto gge_log(const char* text) { return System_Log(text); }
// System_Launch
// Resource
// Ini
// Timer
// Random
// Graph
ccc_bind_declspec auto gge_beginScene(sPointer texture) { return Graph_BeginScene((ggeTexture*)texture); }
// ccc_bind_declspec auto gge_endScene() { return Graph_EndScene(); }
// Audio
// Input


////////////////////////////////////////////////////////////////////////// font
ccc_bind_declspec auto font_create(const char *filename, int fontSize, int createMode) { return (sPointer)Font_Create(filename, fontSize, createMode); }
ccc_bind_declspec auto font_render(sPointer font, float x, float y, const char* text) { return ((ggeFont*)font)->Render(x, y, text); }
ccc_bind_declspec auto font_setColor(sPointer font, guint32 color) { return ((ggeFont*)font)->SetColor(color); }
ccc_bind_declspec auto font_getColor(sPointer font) { return ((ggeFont*)font)->GetColor(); }
ccc_bind_declspec auto font_setShadow(sPointer font) { return ((ggeFont*)font)->SetShadowColor(Color_ARGB(0xFF, 0, 0, 0)); }
static auto font_getWidth(sPointer font, const char *str) 
{ 
	ggeFont::StringInfo info; 
	info.Width = 0;
	((ggeFont*)font)->GetStringInfo(str, info);
	return (int)info.Width;
}
ccc_bind_declspec auto font_release(sPointer font) { return ((ggeFont*)font)->Release(); }

////////////////////////////////////////////////////////////////////////// sprite
ccc_bind_declspec auto sprite_create(sPointer texture) { return (sPointer)Sprite_Create((ggeTexture*)texture); }
ccc_bind_declspec auto sprite_render(sPointer sprite, float x, float y) { return ((ggeSprite*)sprite)->Render(x, y); }
ccc_bind_declspec auto sprite_renderPosition(sPointer sprite) { return ((ggeSprite*)sprite)->RenderPosition(); }
ccc_bind_declspec auto sprite_setColor(sPointer sprite, guint32 color) { return ((ggeSprite*)sprite)->SetColor(color); }
ccc_bind_declspec auto sprite_getColor(sPointer sprite) { return ((ggeSprite*)sprite)->GetColor(); }
ccc_bind_declspec auto sprite_setPosition(sPointer sprite, float x, float y) { return ((ggeSprite*)sprite)->SetPosition(x, y); }
ccc_bind_declspec auto sprite_setPositionEx(sPointer sprite, float x, float y, float scale){ return ((ggeSprite*)sprite)->SetPositionEx(x, y, 0, scale, scale); }
ccc_bind_declspec auto sprite_setTexture(sPointer sprite, sPointer texture) { return ((ggeSprite*)sprite)->SetTexture((ggeTexture*)texture); }
ccc_bind_declspec auto sprite_getTexture(sPointer sprite) { return (sPointer)((ggeSprite*)sprite)->GetTexture(); }
ccc_bind_declspec auto sprite_setTextureRect(sPointer sprite, float x, float y, float w, float h) { return ((ggeSprite*)sprite)->SetTextureRect(x, y, w, h); }
ccc_bind_declspec auto sprite_setHotSpot(sPointer sprite, float x, float y) { return ((ggeSprite*)sprite)->SetHotSpot(x, y); }
ccc_bind_declspec auto sprite_getWidth(sPointer sprite) { return ((ggeSprite*)sprite)->GetWidth(); }
ccc_bind_declspec auto sprite_getHeight(sPointer sprite) { return ((ggeSprite*)sprite)->GetHeight(); }
ccc_bind_declspec auto sprite_release(sPointer sprite) { return ((ggeSprite*)sprite)->Release(); }


////////////////////////////////////////////////////////////////////////// texture
static int s_texture_pitch;
ccc_bind_declspec auto texture_create(int w, int h) { return (sPointer)Texture_Create(w, h); }
ccc_bind_declspec auto texture_file(const char* filename) { return (sPointer)Texture_Load(filename); }
ccc_bind_declspec auto texture_load(sPointer ptr, int size) { return (sPointer)Texture_Load((char*)ptr, size); }
ccc_bind_declspec auto texture_target(int w, int h) { return (sPointer)Texture_CreateRenderTarget(w, h, TARGET_LOCKABLE); }
ccc_bind_declspec auto texture_lock(sPointer texture, bool readolnly, int l, int t, int w, int h) { return ((ggeTexture*)texture)->Lock(readolnly, l, t, w, h, &s_texture_pitch); }
ccc_bind_declspec auto texture_pitch() { return s_texture_pitch; }
ccc_bind_declspec auto texture_unlock(sPointer texture) { return ((ggeTexture*)texture)->Unlock(); }
ccc_bind_declspec auto texture_getWidth(sPointer texture) { return ((ggeTexture*)texture)->GetWidth(); }
ccc_bind_declspec auto texture_getHeight(sPointer texture) { return ((ggeTexture*)texture)->GetHeight(); }
ccc_bind_declspec auto texture_release(sPointer texture) { return ((ggeTexture*)texture)->Release(); }


////////////////////////////////////////////////////////////////////////// music
ccc_bind_declspec auto music_load(const char* filename) { return (sPointer)gge::Music_Load(filename); }
ccc_bind_declspec auto music_volume(sPointer music, int volume) { return ((ggeMusic*)music)->SetVolume(volume); }
ccc_bind_declspec auto music_loop(sPointer music, bool loop) { return ((ggeMusic*)music)->SetLoop(loop); }
ccc_bind_declspec auto music_play(sPointer music) { return ((ggeMusic*)music)->Play(); }
ccc_bind_declspec auto music_pause(sPointer music) { return ((ggeMusic*)music)->Pause(); }
ccc_bind_declspec auto music_stop(sPointer music) { return ((ggeMusic*)music)->Stop(); }
ccc_bind_declspec auto music_playing(sPointer music) { ((ggeMusic*)music)->IsPlaying(); }
ccc_bind_declspec auto music_release(sPointer music) { return ((ggeMusic*)music)->Release(); }



////////////////////////////////////////////////////////////////////////// music
ccc_bind_declspec auto sound_load(const char* filename) { return (sPointer)gge::Sound_Load(filename); }
ccc_bind_declspec auto sound_volume(sPointer sound, int volume) { return ((ggeSound*)sound)->SetVolume(volume); }
ccc_bind_declspec auto sound_loop(sPointer sound, bool loop) { return ((ggeSound*)sound)->SetLoop(loop); }
ccc_bind_declspec auto sound_play(sPointer sound) { return ((ggeSound*)sound)->Play(); }
ccc_bind_declspec auto sound_pause(sPointer sound) { return ((ggeSound*)sound)->Pause(); }
ccc_bind_declspec auto sound_stop(sPointer sound) { return ((ggeSound*)sound)->Stop(); }
ccc_bind_declspec auto sound_playing(sPointer sound) { ((ggeSound*)sound)->IsPlaying(); }
ccc_bind_declspec auto sound_release(sPointer sound) { return ((ggeSound*)sound)->Release(); }


static bool gge_frame()
{
	ccc_en_lock;
	Scheduler::getInstance()->update(Timer_GetDelta());

	lua_getglobal(L, "gge_frame");
#if defined(ccc_use_traceback)
	if (lua_pcall(L, 0, 1, traceback_index) != LUA_OK)
	{
		lua_pop(L, 1);
		ccc_un_lock;
		cAutoReleasePool::getInstance()->clear();
		return false;
	}
#else
	lua_call(L, 0, 1);
#endif
	auto r = lua_toboolean(L, -1);
	lua_pop(L, 1);

	cAutoReleasePool::getInstance()->clear();
	ccc_un_lock;
	return r;
}
static bool gge_exit()
{
	ccc_en_lock;
	lua_getglobal(L, "gge_exit");
#if defined(ccc_use_traceback)
	if (lua_pcall(L, 0, 1, traceback_index) != LUA_OK)
	{
		lua_pop(L, 1);
		ccc_un_lock;
		return false;
	}
#else
	lua_call(L, 0, 1);
#endif
	auto r = lua_toboolean(L, -1);
	lua_pop(L, 1);
	ccc_un_lock;
	return r;
}

static bool gge_message(HWND h, UINT u, WPARAM w, LPARAM l)
{
	ccc_en_lock;
	lua_getglobal(L, "gge_message");
	lua_pushnumber(L, (unsigned long long)h);
	lua_pushnumber(L, (unsigned long long)u);
	lua_pushnumber(L, w);
	lua_pushnumber(L, l);
#if defined(ccc_use_traceback)
	if (lua_pcall(L, 4, 1, traceback_index) != LUA_OK)
	{
		lua_pop(L, 1);
		ccc_un_lock;
		return false;
	}
#else
	lua_call(L, 4, 1);
#endif
	auto r = lua_toboolean(L, -1);
	lua_pop(L, 1);
	ccc_un_lock;
	return r;
}



void registerGGE(lua_State* state)
{
	ccc_register_func(gge_createEngine);

	ccc_register_func(gge_callback);
	ccc_register_func(gge_setWindowSize);
	ccc_register_func(gge_hideMouse);
	ccc_register_func(gge_debugLog);
	ccc_register_func(gge_forceTexturefilter);
	ccc_register_func(gge_setWindowTitle);
	ccc_register_func(gge_getHwnd);

	// System_Log
	ccc_register_func(gge_log);
	// System_Launch
	ccc_register_func(System_Launch);
	// Resource
	// Ini
	ccc_register_func(Ini_SetFile);
	ccc_register_func(Ini_SetInt);
	ccc_register_func(Ini_GetInt);
	ccc_register_func(Ini_SetFloat);
	ccc_register_func(Ini_GetFloat);
	ccc_register_func(Ini_SetString);
	ccc_register_func(Ini_GetString);
	// Timer
	ccc_register_func(Timer_GetDelta);
	ccc_register_func(Timer_GetTime);
	// Random
	ccc_register_func(Random_Int);
	// Graph
	ccc_register_func(Graph_Clear);
	ccc_register_func(gge_beginScene);
	ccc_register_func(Graph_EndScene);
	// Audio
	// Input
	ccc_register_func(Input_GetMousePosX);
	ccc_register_func(Input_GetMousePosY);
	ccc_register_func(Input_IsKeyPress);
	ccc_register_func(Input_IsKeyUp);
	ccc_register_func(Input_IsKeyDown);
	ccc_register_func(Input_IsMousePress);
	ccc_register_func(Input_IsMouseUp);
	ccc_register_func(Input_IsMouseDown);
	ccc_register_func(Input_GetMouseWheel);
	ccc_register_func(Input_GetChar);

	// color
	ccc_register_func(Color_ARGB);


	ccc_register_func(font_create);
	ccc_register_func(font_render);
	ccc_register_func(font_setColor);
	ccc_register_func(font_getColor);
	ccc_register_func(font_setShadow);
	ccc_register_func(font_getWidth);
	ccc_register_func(font_release);

	// sound

	ccc_register_func(sprite_create);
	ccc_register_func(sprite_render);
	ccc_register_func(sprite_renderPosition);
	ccc_register_func(sprite_setColor);
	ccc_register_func(sprite_getColor);
	ccc_register_func(sprite_setPosition);
	ccc_register_func(sprite_setPositionEx);
	ccc_register_func(sprite_setTexture);
	ccc_register_func(sprite_getTexture);
	ccc_register_func(sprite_setTextureRect);
	ccc_register_func(sprite_setHotSpot);
	ccc_register_func(sprite_getWidth);
	ccc_register_func(sprite_getHeight);
	ccc_register_func(sprite_release);


	ccc_register_func(texture_create);
	ccc_register_func(texture_file);
	ccc_register_func(texture_load);
	ccc_register_func(texture_target);
	ccc_register_func(texture_lock);
	ccc_register_func(texture_pitch);
	ccc_register_func(texture_unlock);
	ccc_register_func(texture_getWidth);
	ccc_register_func(texture_getHeight);
	ccc_register_func(texture_release);


	ccc_register_func(music_load);
	ccc_register_func(music_volume);
	ccc_register_func(music_loop);
	ccc_register_func(music_play);
	ccc_register_func(music_pause);
	ccc_register_func(music_stop);
	ccc_register_func(music_playing);
	ccc_register_func(music_release);

	ccc_register_func(sound_load);
	ccc_register_func(sound_volume);
	ccc_register_func(sound_loop);
	ccc_register_func(sound_play);
	ccc_register_func(sound_pause);
	ccc_register_func(sound_stop);
	ccc_register_func(sound_playing);
	ccc_register_func(sound_release);


	ccc_register_func(Variant_Asc2Utf8);
	ccc_register_func(Variant_Utf82Asc);
}

